package com.example.artemis.config;

import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServers;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

/**
 * Embedded ActiveMQ Artemis server configuration
 * Provides persistent message storage and queue management
 */
public class EmbeddedServerConfig {
    private static final Logger logger = LoggerFactory.getLogger(EmbeddedServerConfig.class);

    // 数据存储路径配置
    private static final String DATA_BASE_PATH = "data";
    private static final String JOURNAL_DIR_PATH = DATA_BASE_PATH + "/journal";
    private static final String BINDINGS_DIR_PATH = DATA_BASE_PATH + "/bindings";
    private static final String LARGE_MESSAGES_DIR_PATH = DATA_BASE_PATH + "/large-messages";

    // Queue sharding configuration
    public static final String QUEUE_PREFIX = "demo.queue.";
    public static final int NUMBER_OF_QUEUES = 5;
    public static final String[] QUEUE_NAMES = Arrays.stream(new int[NUMBER_OF_QUEUES])
            .mapToObj(i -> QUEUE_PREFIX + i)
            .toArray(String[]::new);

    // Persistence and disk management configuration
    public static final long MAX_DISK_USAGE_PERCENTAGE = 85; // 85% max disk usage
    public static final long MAX_QUEUE_SIZE_BYTES = 1024 * 1024 * 1024; // 1G per queue
    public static final int JOURNAL_SYNC_TIMEOUT = 30000; // 30 seconds sync timeout

    private ActiveMQServer server;

    /**
     * Create and configure the embedded ActiveMQ Artemis server
     * @return Configured ActiveMQServer instance
     */
    public ActiveMQServer createServer() {
        try {
            Configuration config = new ConfigurationImpl()
                    // Enhanced persistence configuration
                    .setPersistenceEnabled(true)
                    .setJournalDirectory(JOURNAL_DIR_PATH)
                    .setBindingsDirectory(BINDINGS_DIR_PATH)
                    .setLargeMessagesDirectory(LARGE_MESSAGES_DIR_PATH)
                    .setJournalSyncNonTransactional(true)
                    .setJournalSyncTransactional(true)
                    .setJournalCompactMinFiles(10)
                    .setJournalCompactPercentage(30)
                    .setMaxDiskUsage((int) MAX_DISK_USAGE_PERCENTAGE)
                    // Enhanced durability settings
                    .setCreateBindingsDir(true)
                    .setCreateJournalDir(true)
                    .setJournalType(org.apache.activemq.artemis.core.server.JournalType.ASYNCIO)
                    // Acceptors configuration
                    .addAcceptorConfiguration("in-vm", "vm://0")

                    // Security configuration (disabled for demo)
                    .setSecurityEnabled(false)

                    // Critical system settings for reliability
                    .setIDCacheSize(20000)
                    .setPersistIDCache(true)
                    .setPersistDeliveryCountBeforeDelivery(true);

            // Create server instance
            server = ActiveMQServers.newActiveMQServer(config);

            // Configure address settings for our queues
            configureAddressSettings();

            logger.info("Embedded ActiveMQ Artemis server configuration created successfully");
            return server;

        } catch (Exception e) {
            logger.error("Failed to create embedded server configuration", e);
            throw new RuntimeException("Failed to create embedded server", e);
        }
    }

    /**
     * Configure address settings for message persistence and delivery
     */
    private void configureAddressSettings() {
        try {
            AddressSettings addressSettings = new AddressSettings()
                    // Enable persistence with enhanced durability
                    .setAutoCreateAddresses(true)
                    .setAutoCreateQueues(true)
                    .setAutoDeleteAddresses(false)
                    .setAutoDeleteQueues(false)

                    // Enhanced redelivery settings for at-least-once delivery
                    .setMaxDeliveryAttempts(5) // Increased retry attempts
                    .setRedeliveryDelay(1000)
                    .setRedeliveryMultiplier(1.5) // More conservative backoff
                    .setMaxRedeliveryDelay(60000) // 1 minute max delay

                    // Disk usage and queue management
                    .setMaxSizeBytes(MAX_QUEUE_SIZE_BYTES) // Per-queue size limit

                    // Message expiration and dead letter queue configuration
                    .setDeadLetterAddress(SimpleString.toSimpleString("DLQ"))
                    .setExpiryAddress(SimpleString.toSimpleString("ExpiryQueue"))
                    .setSendToDLAOnNoRoute(true)

                    // Message persistence settings
                    .setRedistributionDelay(0); // Immediate redistribution

            // Apply settings to all demo queue addresses
            for (String queueName : QUEUE_NAMES) {
                server.getAddressSettingsRepository()
                        .addMatch(queueName + "#", addressSettings);
            }

            logger.info("Address settings configured for {} queues", NUMBER_OF_QUEUES);
        } catch (Exception e) {
            logger.warn("Could not configure address settings: {}", e.getMessage());
        }
    }

    /**
     * Start the embedded server
     */
    public void start() {
        if (server == null) {
            throw new IllegalStateException("Server not created. Call createServer() first.");
        }

        try {
            server.start();
            logger.info("Embedded ActiveMQ Artemis server started successfully");

            // Wait a moment for server to be fully started
            Thread.sleep(1000);

        } catch (Exception e) {
            logger.error("Failed to start embedded server", e);
            throw new RuntimeException("Failed to start embedded server", e);
        }
    }

    /**
     * Stop the embedded server
     */
    public void stop() {
        if (server != null && server.isStarted()) {
            try {
                server.stop();
                logger.info("Embedded ActiveMQ Artemis server stopped successfully");
            } catch (Exception e) {
                logger.error("Failed to stop embedded server", e);
            }
        }
    }

    /**
     * Get server instance
     */
    public ActiveMQServer getServer() {
        return server;
    }

    /**
     * Check if server is running
     */
    public boolean isRunning() {
        return server != null && server.isStarted();
    }
}